﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SisalSandbox
{
    class Program
    {
        static void Main(string[] args) {
            Graph g = new Graph();
            AssignCosts(g);
        }

        static void AssignCosts(Graph g) {
            foreach(Node node in g.N) {
                if(node is ParallelNode) {

                    ParallelNode pn = node as ParallelNode;
                    AssignCosts(pn.G);
                    pn.Ft = pn.F * pn.G.Ft;

                } else if(node is CompoundNode) {

                    CompoundNode cn = node as CompoundNode;
                    foreach(Graph sub in cn.SubGraphs) {
                        AssignCosts(sub);
                    }
                    cn.Ft = cn.SubGraphs.Sum(i => i.F * i.Ft);

                }
            }

            g.Ft = g.N.Sum(n => n.Ft);
        }

        static void InitCalls(Graph g, int f) {
            foreach(Node n in g.N) {
                if(n is FunctionCallNode) {
                    
                    //TODO: FIXME!

                } else if(n is ParallelNode) {

                    ParallelNode pn = n as ParallelNode;
                    InitCalls(pn.G, f * pn.F);

                } else if(n is CompoundNode) {

                    CompoundNode cn = n as CompoundNode;
                    foreach(Graph sub in cn.SubGraphs) {
                        InitCalls(sub, f * sub.F);
                    }

                }
            }
        }

        static void AssignInternalCalls(Graph g, int I) {
            foreach(Node n in g.N) {
                if(n is FunctionCallNode) {

                } else if(n is ParallelNode) {

                    ParallelNode pn = n as ParallelNode;
                    AssignInternalCalls(pn.G, I);

                } else if(n is CompoundNode) {

                    CompoundNode cn = n as CompoundNode;
                    foreach(Graph sub in cn.SubGraphs) {
                        AssignInternalCalls(sub, I);
                    }

                }
            }
        }

    }

    abstract class Node
    {
        //Execution Time Cost Function
        public abstract int Ft { get; set; }
    }

    abstract class OutputNode<T> : Node { }

    abstract class SimpleOutputNode<T> : OutputNode<T> { }

    abstract class CompoundOutputNode<T> : OutputNode<T> { }

    abstract class SimpleNode : Node { }

    class CompoundNode : Node
    {
        public List<Graph> SubGraphs { get; set; }

        public override int Ft {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }
    }

    class ArraySizeNode : SimpleOutputNode<int>
    {
        public string ArrayVar { get; set; }
    }

    class BinNode<T> : SimpleOutputNode<T>
    {
        public string Operator { get; set; }
        public Node Left { get; set; }
        public Node Right { get; set; }
    }

    class BottomNode : SimpleOutputNode<Node>
    {
        public Node Output { get; set; }
    }

    class TopNode<T> : SimpleOutputNode<T>
    {
        public T Input { get; set; }
    }

    class ConstNode<T> : SimpleOutputNode<T>
    {
        public T Value { get; set; }
    }

    class VarNode : SimpleNode
    {
        public string Name { get; set; }
    }

    class IfThenElseNode : CompoundNode
    {
        public SimpleOutputNode<bool> Cond { get; set; }
        public Node TBranch { get; set; }
        public Node FBranch { get; set; }
    }

    class FunctionCallNode : Node
    {
        public string Name { get; set; }
        public List<Node> Args { get; set; }
    }

    class Function : SimpleNode
    {
        public Node Body { get; set; }
    }

    class ParallelNode : Node
    {
        public Graph G { get; set; }        //Sub Graph
        public int F { get; set; }          //Frequency Count

        public override int Ft {
            get { throw new NotImplementedException(); }
            set { throw new NotImplementedException(); }
        }
    }

    class Test
    {
        public Node GetTestExpr() {

            Function split = new Function {
                Body = 
            }

            Function qsort = new Function {
                Body = new IfThenElseNode {
                    Cond = new BinNode<bool> {
                        Operator = "<",
                        Left = new ArraySizeNode { ArrayVar = "data" },
                        Right = new ConstNode<int> { Value = 2 }
                    },
                    TBranch = new BottomNode {
                        Output = new VarNode { Name = "data" }
                    },
                    FBranch = new FunctionCallNode {
                        Name = "Split",
                        Args = new List<Node> {
                            new VarNode { Name = "data" }
                        }
                    }
                }
            };
        }

        //public void A(Node n) {
        //    if(n is BinNode) {
        //        BinNode bn = n as BinNode;
        //        switch(bn.Operator) {
        //            case "+": break;
        //            case "-": break;
        //            case "*": break;
        //            case "/": break;
        //            case "<": break;
        //            case ">": break;
        //        }
        //    }
        //}
    }






    class Edge
    {

    }

    class Graph
    {
        public List<Node> N { get; set; }      //Node set
        public Node Start { get; set; }        //Start Node
        public Node End { get; set; }          //End Node
        public List<Edge> Ec { get; set; }     //Communication Edges

        public Graph() {
            N = new List<Node>();
        }

        //Communication Size Cost Function
        public int Fc(Node node, int port) {
            throw new NotImplementedException();
        }

        //Execution Time Cost Function
        public int Ft { get; set; }

        public int F { get; set; }              //Execution Frequency

        public Graph GetCG() {
            List<Node> nodes = new List<Node>();

            foreach(Node node in N) {
                if(node is )
            }
        }
    }
}
